package wangwenjun.phase2.concurrencypattern.future;

import lombok.extern.slf4j.Slf4j;

/**
 * @author ChangLiang
 * @date 2020/6/15
 */
@Slf4j
public class FutureImpl<T> implements Future<T> {

    /**
     * 计算结果
     */
    private T result;

    /**
     * 任务是否完成
     */
    private boolean isDone = false;

    /**
     * 定义对象锁
     */
    private final Object MUTEX = new Object();


    /*
    FutureImpl 中充分利用了线程间的通信wait 和notifyAll ，
    当任务没有被完成之前通过get 方法获取结果， 调用者会进入阻塞，
    直到任务完成并接收到其他线程的唤醒信号，
    finish方法接收到了任务完成通知，唤醒了因调用get 而进入阻塞的线程。
    */

    @Override
    public T get() throws InterruptedException {
        log.error("Thread:{} begin to execute FutureImpl#get", Thread.currentThread());
        synchronized (MUTEX) {
            // 当任务还没完成时，调用get方法会被挂起而进入阻塞
            while (!isDone) {
                log.error("Thread:{} begin to execute Mutex#wait", Thread.currentThread());
                // output: Thread:Thread[main,5,main] execution begin to wait
                // 注意这里是main线程进入wait状态 不影响FUTURE-0线程
                MUTEX.wait();
            }
            log.error("Thread:{} finish to execute Mutex#wait", Thread.currentThread());
            return result;
        }
    }

    /**
     * 执行结束后 将返回结果通过finish传递给Future
     * @param result
     */
    public void finish(T result) {
        log.warn("Thread:{} begin to execute FutureImpl#finish", Thread.currentThread());
        synchronized (MUTEX) {
            // balking 设计模式
            if (isDone) {
                return;
            }
            // 计算完成， 为result 指定结果， 并且将isDone 设为true ，同时唤醒阻塞中的线程
            log.warn("Thread:{} finish to execute FutureImpl#finish", Thread.currentThread());
            this.result = result;
            this.isDone = true;
            MUTEX.notifyAll();
        }
    }

    @Override
    public boolean isFinished() {
        return isDone;
    }

}
